home *** CD-ROM | disk | FTP | other *** search
/ BCI NET 2 / BCI NET 2.iso / archives / programming / c / hce.lha / HCE / LibSource / clib / Math / src / _printf.c next >
Encoding:
C/C++ Source or Header  |  1992-09-02  |  9.1 KB  |  590 lines

  1. #include <stdio.h>
  2. #include <ctype.h>
  3. #include <string.h>
  4.  
  5. /* From the Hcc.lib by Detlef Wurkner. */
  6. #define    FALSE    (0)
  7. #define TRUE    (!FALSE)
  8.  
  9. static char    _numstr[] = "0123456789ABCDEF";
  10.  
  11. static char *_strlwr(string)
  12.     register char *string;
  13.     {
  14.     register char *p = string;
  15.  
  16.     while(*string)
  17.         tolower(*string++);
  18.     return(p);
  19.     }
  20.  
  21. static char *_ultoa(n, buffer, radix)
  22.     register unsigned long n;
  23.     register char *buffer;
  24.     register int radix;
  25.     {
  26.     register char *p = buffer;
  27.  
  28.     do
  29.         {
  30.         *p++ = _numstr[n % radix];    /* grab each digit */
  31.         }
  32.         while((n /= radix) > 0);
  33.     *p = '\0';
  34.     return(strrev(buffer));            /* reverse and return it */
  35.     }
  36.  
  37. static char *_ltoa(n, buffer, radix)
  38.     register long n;
  39.     register char *buffer;
  40.     int radix;
  41.     {
  42.     register char *p = buffer;
  43.  
  44.     if (n < 0)
  45.         {
  46.         *p++ = '-';
  47.         n = -n;
  48.         }
  49.     _ultoa(n, p, radix);
  50.     return(buffer);
  51.     }
  52.  
  53. static _prtfld(op, put, buf, ljustf, sign, pad, width, preci)
  54.     register char *op;
  55.     register int (*put)();
  56.     register unsigned char *buf;
  57.     int ljustf;
  58.     register char sign;
  59.     char pad;
  60.     register int width;
  61.     int preci;
  62. /*
  63.  *    Output the given field in the manner specified by the arguments.
  64.  *    Return the number of characters output.
  65.  */
  66.     {
  67.     register int cnt = 0, len;
  68.     register unsigned char ch;
  69.  
  70.     len = strlen(buf);
  71.  
  72.     if (*buf == '-')
  73.         sign = *buf++;
  74.     else if (sign)
  75.         len++;
  76.  
  77.     if ((preci != -1) && (len > preci))    /* limit max data width */
  78.         len = preci;
  79.  
  80.     if (width < len)    /* flexible field width or width overflow */
  81.         width = len;
  82.  
  83. /* at this point:
  84.  *    width = total field width
  85.  *    len   = actual data width (including possible sign character)
  86.  */
  87.     cnt = width;
  88.     width -= len;
  89.  
  90.     while (width || len)
  91.         {
  92.         if (!ljustf && width)        /* left padding */
  93.             {
  94.             if (len && sign && (pad == '0'))
  95.                 goto showsign;
  96.             ch = pad;
  97.             --width;
  98.             }
  99.         else if (len)
  100.             {
  101.             if (sign)
  102.                 {
  103. showsign:            ch = sign;    /* sign */
  104.                 sign = '\0';
  105.                 }
  106.             else
  107.                 ch = *buf++;    /* main field */
  108.             --len;
  109.             }
  110.         else
  111.             {
  112.             ch = pad;        /* right padding */
  113.             --width;
  114.             }
  115.         (*put)(ch, op);
  116.         }
  117.  
  118.     return(cnt);
  119.     }
  120.  
  121.  
  122. _printf(op, put, fmt, args)
  123.     char *op;
  124.     unsigned int (*put)();
  125.     register unsigned char *fmt;
  126.     register unsigned int *args;
  127.     {
  128.     register int i, cnt = 0, ljustf, lval;
  129.     int preci, dpoint, width;
  130.     char pad, sign, radix;
  131.     register char *ptmp;
  132.     char tmp[64], *_ltoa(), *_ultoa();
  133.     double fx;
  134.  
  135.     while(*fmt)
  136.         {
  137.         if(*fmt == '%')
  138.             {
  139.             ljustf = FALSE;    /* left justify flag */
  140.             sign = '\0';    /* sign char & status */
  141.             pad = ' ';    /* justification padding char */
  142.             width = -1;    /* min field width */
  143.             dpoint = FALSE;    /* found decimal point */
  144.             preci = -1;    /* max data width */
  145.             radix = 10;    /* number base */
  146.             ptmp = tmp;    /* pointer to area to print */
  147.             lval = FALSE;    /* long value flaged */
  148. fmtnxt:
  149.             i = 0;
  150.             while (isdigit(*++fmt))
  151.                 {
  152.                 i = (i * 10) + (*fmt - '0');
  153.                 if (dpoint)
  154.                     preci = i;
  155.                 else if (!i && (pad == ' '))
  156.                     {
  157.                     pad = '0';
  158.                     goto fmtnxt;
  159.                     }
  160.                 else
  161.                     width = i;
  162.                 }
  163.  
  164.             switch(*fmt)
  165.                 {
  166.                 case '\0':    /* early EOS */
  167.                     --fmt;
  168.                     goto charout;
  169.  
  170.                 case '-':    /* left justification */
  171.                     ljustf = TRUE;
  172.                     goto fmtnxt;
  173.  
  174.                 case ' ':
  175.                 case '+':    /* leading sign flag */
  176.                     sign = *fmt;
  177.                     goto fmtnxt;
  178.  
  179.                 case '*':    /* parameter width value */
  180.                     i = *args++;
  181.                     if (dpoint)
  182.                         preci = i;
  183.                     else
  184.                         width = i;
  185.                     goto fmtnxt;
  186.  
  187.                 case '.':    /* secondary width field */
  188.                     dpoint = TRUE;
  189.                     goto fmtnxt;
  190.  
  191.                 case 'l':    /* long data */
  192.                     lval = TRUE;
  193.                     goto fmtnxt;
  194.  
  195.                 case 'd':    /* Signed decimal */
  196.                 case 'i':
  197.                     _ltoa((long)((lval)
  198.                         ?(*((long *) args))
  199.                         :(*((int  *) args))),
  200.                           ptmp, 10);
  201.                     if(lval)
  202.                         args = ((unsigned int *)
  203.                             (((long *) args) + 1));
  204.                     else
  205.                         args = ((unsigned int *)
  206.                             (((int *) args) + 1));
  207.                     goto printit;
  208.  
  209.                 case 'b':    /* Unsigned binary */
  210.                     radix = 2;
  211.                     goto usproc;
  212.  
  213.                 case 'o':    /* Unsigned octal */
  214.                     radix = 8;
  215.                     goto usproc;
  216.  
  217.                 case 'p':    /* Pointer */
  218.                     lval = TRUE;
  219.                     pad = '0';
  220.                     width = 6;
  221.                     preci = 8;
  222.                     /* fall thru */
  223.  
  224.                 case 'x':    /* Unsigned hexadecimal */
  225.                 case 'X':
  226.                     radix = 16;
  227.                     /* fall thru */
  228.  
  229.                 case 'u':    /* Unsigned decimal */
  230. usproc:
  231.                     _ultoa((unsigned long)((lval)
  232.                         ?(*((unsigned long *) args))
  233.                         : *args++ ),
  234.                           ptmp, radix);
  235.                     if(lval)
  236.                         args = ((unsigned int *)
  237.                         (((unsigned long *) args) + 1));
  238.                     if (*fmt == 'x')
  239.                         _strlwr(ptmp);
  240.                     goto printit;
  241.  
  242.                 case 'e':    /* float */
  243.                 case 'f':
  244.                 case 'g':
  245.                 case 'E':
  246.                 case 'G':
  247.                     fx = *((double *) args);
  248.                     args=(unsigned int *)
  249.                          (((double *) args)+1);
  250.  
  251.                     fp_print(fx, *fmt, preci, ptmp);
  252.                     preci = -1;
  253.                     goto printit;
  254.  
  255.                 case 'c':    /* Character */
  256.                     ptmp[0] = *args++;
  257.                     ptmp[1] = '\0';
  258.                     goto nopad;
  259.  
  260.                 case 's':    /* String */
  261.                     ptmp = *((char **) args);
  262.                     args = ((unsigned int *)
  263.                         (((char **) args) + 1));
  264. nopad:
  265.                     sign = '\0';
  266.                     pad  = ' ';
  267. printit:
  268.                     cnt += _prtfld(op, put, ptmp, ljustf,
  269.                                sign, pad, width, preci);
  270.                     break;
  271.  
  272.                 default:    /* unknown character */
  273.                     goto charout;
  274.                 }
  275.             }
  276.         else
  277.             {
  278. charout:
  279.             (*put)(*fmt, op);        /* normal char out */
  280.             ++cnt;
  281.             }
  282.         ++fmt;
  283.         }
  284.     return(cnt);
  285.     }
  286.  
  287.  
  288. #define MAXEC    40
  289.  
  290. static char *f_buf;
  291. static int f_upper;
  292.  
  293. static char ec_buf[MAXEC+10];
  294. static int ec_sign, ec_exp;
  295.  
  296. static fp_print(x, fmtc, prec, ptmp)
  297. float x;
  298. char *ptmp;
  299. {
  300.     f_buf = ptmp;
  301.     f_upper = 0;
  302.  
  303.     switch (fmtc) {
  304.     case 'E':
  305.         f_upper = 1;
  306.     case 'e':
  307.         e_print(x, prec);
  308.         break;
  309.     case 'F':
  310.     case 'f':
  311.         f_print(x, prec);
  312.         break;
  313.     case 'G':
  314.         f_upper = 1;
  315.     case 'g':
  316.         g_print(x, prec);
  317.         break;
  318.     }
  319. }
  320.  
  321. static
  322. e_print(x, prec)
  323. float x;
  324. {
  325.     int nsig;
  326.     register char *p;
  327.  
  328.     if (prec < 0)
  329.         nsig = 7;
  330.     else
  331.         nsig = prec+1;
  332.  
  333.     ec_pr(x, nsig, 0);
  334.  
  335.     p = f_buf;
  336.     if (ec_sign)
  337.         *p++ = '-';
  338.     *p++ = ec_buf[0];
  339.     *p++ = '.';
  340.     if (nsig > 1)
  341.         strcpy(p, &ec_buf[1]);
  342.     p += strlen(p);
  343.     *p++ = f_upper ? 'E' : 'e';
  344.     ec_exp--;
  345.     if (ec_exp < 0) {
  346.         *p++ = '-';
  347.         ec_exp = -ec_exp;
  348.     }
  349.     if (ec_exp < 10)
  350.         *p++ = '0';
  351.     sprintf(p, "%d", ec_exp);
  352. }
  353.  
  354. static
  355. f_print(x, prec)
  356. float x;
  357. {
  358.     int nsig, nz, i;
  359.     register char *p;
  360.  
  361.     if (prec < 0)
  362.         nsig = 6;
  363.     else
  364.         nsig = prec;
  365.  
  366.     ec_pr(x, -nsig, 0);
  367.  
  368.     p = f_buf;
  369.     if (ec_sign)
  370.         *p++ = '-';
  371.     if (ec_exp < 1) {
  372.         *p++ = '0';
  373.     } else {
  374.         strncpy(p, ec_buf, ec_exp);
  375.         p += ec_exp;
  376.     }
  377.     if (prec != 0 || nsig)
  378.         *p++ = '.';
  379.     if (nsig == 0) {
  380.         *p = 0;
  381.         return;
  382.     }
  383.  
  384.     if (ec_exp < 0) {
  385.         nz = -ec_exp;
  386.         if (nz > nsig)
  387.             nz = nsig;
  388.         for (i=0; i<nz; i++)
  389.             *p++ = '0';
  390.         nsig -= nz;
  391.         if (nsig > 0) {
  392.             strncpy(p, ec_buf, nsig);
  393.             p += nsig;
  394.         }
  395.         *p = 0;
  396.     } else {
  397.         strcpy(p, &ec_buf[ec_exp]);
  398.     }
  399. }
  400.  
  401. static
  402. g_print(x, nsig)
  403. float x;
  404. {
  405.     int prec;
  406.  
  407.     if (nsig < 0)
  408.         nsig = 6;
  409.     if (nsig < 1)
  410.         nsig = 1;
  411.  
  412.     ec_pr(x, 1, 1);
  413.  
  414.     if (ec_exp < -3 || ec_exp > nsig)
  415.         e_print(x, nsig-1);
  416.     else {
  417.         prec = nsig - ec_exp;
  418.         f_print(x, prec);
  419.     }
  420. }
  421.  
  422. /*
  423.  * given x, ndig
  424.  *    if ndig is > 0, indicates number of significant digits
  425.  *    else -ndig is number of digits we want to the right of dec. pt.
  426.  * return the following:
  427.  *    appropriate number of digits of significance in ec_buf
  428.  *    ec_sign true if x was negative
  429.  *    ec_exp indicates the decimal point relative to leftmost digit
  430.  */
  431. static
  432. ec_pr(x, ndig, trunc)
  433. float x;
  434. {
  435.     int isneg;
  436.     int nhave;
  437.     long part;
  438.     int exp, newexp;
  439.     float rem;
  440.     char tbuf[20];
  441.  
  442.     /* ndig must be >= 1 and <= MAXEC */
  443.     if (x < 0.0) {
  444.         isneg = 1;
  445.         x = -x;
  446.     } else
  447.         isneg = 0;
  448.  
  449.     /* get some digits */
  450.     somedig(x, &part, &rem, &exp);
  451.  
  452.     sprintf(ec_buf, "%ld", part);
  453.     nhave = strlen(ec_buf);
  454.     exp = nhave + exp;
  455.  
  456.     if (ndig <= 0) {
  457.         ndig = -ndig;
  458.         ndig += exp;
  459.     }
  460.  
  461.     if (ndig < 1)
  462.         ndig = 1;
  463.     else if (ndig > MAXEC)
  464.         ndig = MAXEC;
  465.  
  466.     /* get some more digits */
  467.     while (nhave < ndig+1 && nhave < MAXEC) {
  468.         if (rem == 0.0) {
  469.             while (nhave < ndig+1)
  470.                 ec_buf[nhave++] = '0';
  471.             ec_buf[nhave] = 0;
  472.             break;
  473.         }
  474.  
  475.         x = rem;
  476.         somedig(x, &part, &rem, &newexp);
  477.  
  478.         sprintf(tbuf, "%ld", part);
  479.         newexp = strlen(tbuf) + newexp;
  480.         while (newexp++)
  481.             ec_buf[nhave++] = '0';
  482.         strcpy(&ec_buf[nhave], tbuf);
  483.         nhave = strlen(ec_buf);
  484.     }
  485.  
  486.     fround(ndig, trunc);
  487.     ec_sign = isneg;
  488.     ec_exp = exp;
  489. }
  490.  
  491. static
  492. fround(n, trunc)
  493. {
  494.     char *p;
  495.  
  496.     p = &ec_buf[n];
  497.     if (*p >= '5' && !trunc) {
  498.         p--;
  499.         while (p >= ec_buf) {
  500.             *p += 1;
  501.             if (*p < '9')
  502.                 goto done;
  503.             *p = '0';
  504.             p--;
  505.         }
  506.         ec_buf[0] = '1';
  507.     }
  508. done:
  509.     ec_buf[n] = 0;
  510. }
  511.  
  512. static
  513. somedig(x, lp, remp, expp)
  514. float x;
  515. long *lp;
  516. float *remp;
  517. int *expp;
  518. {
  519.     int bexp, dexp;
  520.     long ipart;
  521.     float rem;
  522.  
  523.     bexp = fgetexp(x);
  524.     dexp = 0;
  525.  
  526.     while (bexp > 31) {
  527.         x *= 1E-3;
  528.         dexp += 3;
  529.         bexp = fgetexp(x);
  530.     }
  531.     while (bexp < 10) {
  532.         x *= 1E3;
  533.         dexp -= 3;
  534.         if (dexp < -24) {
  535.             ipart = 0;
  536.             dexp = 0;
  537.             rem = 0.0;
  538.             goto iszero;
  539.         }
  540.         bexp = fgetexp(x);
  541.     }
  542.     fsplit(x, &ipart, &rem);
  543. iszero:
  544.     *lp = ipart;
  545.     *remp = rem;
  546.     *expp = dexp;
  547. }
  548.  
  549. static
  550. fgetexp(x)
  551. float x;
  552. {
  553.     char *p;
  554.     int i;
  555.  
  556.     p = (char *)&x;
  557.     i = p[3] & 0x7f;
  558.     i -= 0x40;
  559.     return i;
  560. }
  561.  
  562. static
  563. fsplit(x, vp, rp)
  564. float x, *rp;
  565. long *vp;
  566. {
  567.     long ival;
  568.     float rem;
  569.     int bexp, neg;
  570.  
  571.     ival = *(long *)&x;
  572.     neg = ival & 0x80;
  573.     ival &= ~0xff;
  574.  
  575.     bexp = fgetexp(x);
  576.  
  577.     if (bexp < 1) {
  578.         ival = 0;
  579.         rem = x;
  580.     } else {
  581.         ival = (unsigned long)ival >> (32-bexp);
  582.         if (neg)
  583.             ival = -ival;
  584.         rem = x - (float)ival;
  585.     }
  586.  
  587.     *vp = ival;
  588.     *rp = rem;    
  589. }
  590.